package com.smartfast4j.manager.modules.sys.service.impl;

import com.smartfast4j.common.Constants;
import com.smartfast4j.common.annotation.PermissionLimit;
import com.smartfast4j.manager.modules.sys.service.SysResourcePermissionService;
import com.smartfast4j.manager.modules.sys.service.SysResourceService;
import com.smartfast4j.manager.modules.sys.service.SysRoleResourceService;
import com.smartfast4j.mapper.sys.SysResourcePermissionMapper;
import com.smartfast4j.pojo.sys.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import java.lang.reflect.Method;
import java.util.*;

@Service
public class SysResourcePermissionServiceImpl implements SysResourcePermissionService {
    @Autowired
    private SysResourcePermissionMapper sysResourcePermissionMapper;

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    private SysResourceService sysResourceService;

    @Autowired
    private SysRoleResourceService sysRoleResourceService;

    private static final Logger logger = LoggerFactory.getLogger(SysResourcePermissionServiceImpl.class);

    public int countByExample(SysResourcePermissionExample example) {
        int count = this.sysResourcePermissionMapper.countByExample(example);
        logger.debug("count: {}", count);
        return count;
    }

    public SysResourcePermission selectByPrimaryKey(Long id) {
        return this.sysResourcePermissionMapper.selectByPrimaryKey(id);
    }

    public List<SysResourcePermission> selectByExample(SysResourcePermissionExample example) {
        return this.sysResourcePermissionMapper.selectByExample(example);
    }

    public int deleteByPrimaryKey(Long id) {
        return this.sysResourcePermissionMapper.deleteByPrimaryKey(id);
    }

    public int updateByPrimaryKeySelective(SysResourcePermission record) {
        return this.sysResourcePermissionMapper.updateByPrimaryKeySelective(record);
    }

    public int updateByPrimaryKey(SysResourcePermission record) {
        return this.sysResourcePermissionMapper.updateByPrimaryKey(record);
    }

    public int deleteByExample(SysResourcePermissionExample example) {
        return this.sysResourcePermissionMapper.deleteByExample(example);
    }

    public int updateByExampleSelective(SysResourcePermission record, SysResourcePermissionExample example) {
        return this.sysResourcePermissionMapper.updateByExampleSelective(record, example);
    }

    public int updateByExample(SysResourcePermission record, SysResourcePermissionExample example) {
        return this.sysResourcePermissionMapper.updateByExample(record, example);
    }

    public int insert(SysResourcePermission record) {
        return this.sysResourcePermissionMapper.insert(record);
    }

    public int insertSelective(SysResourcePermission record) {
        return this.sysResourcePermissionMapper.insertSelective(record);
    }

    public int insertBatchSelective(List<SysResourcePermission> records) {
        return this.sysResourcePermissionMapper.insertBatchSelective(records);
    }

    public int updateBatchByPrimaryKeySelective(List<SysResourcePermission> records) {
        return this.sysResourcePermissionMapper.updateBatchByPrimaryKeySelective(records);
    }

    @Transactional
    @Override
    public List<SysResourcePermission> init() {
        deleteByExample(null);//先删除旧的
        AbstractHandlerMethodMapping<RequestMappingInfo> objHandlerMethodMapping = (AbstractHandlerMethodMapping<RequestMappingInfo>)applicationContext.getBean("requestMappingHandlerMapping");
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = objHandlerMethodMapping.getHandlerMethods();
        List<SysResourcePermission> sysResourcePermissions = new ArrayList<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> requestMappingInfoHandlerMethodEntry : handlerMethods.entrySet()) {
            RequestMappingInfo requestMappingInfo = requestMappingInfoHandlerMethodEntry.getKey();
            HandlerMethod mappingInfoValue = requestMappingInfoHandlerMethodEntry.getValue();
            //标注了这个注解的Controller类表示需要做访问权限控制
            PermissionLimit permissionLimit = mappingInfoValue.getBeanType().getAnnotation(PermissionLimit.class);
            if(permissionLimit ==null){
                continue;
            }
            RequestMethodsRequestCondition methodsCondition = requestMappingInfo.getMethodsCondition();
            //资源的Http访问请求方式
            Set<RequestMethod> methodSet = methodsCondition.getMethods();
            String methods = "";
            for (RequestMethod method : methodSet){
                methods += method.name()+",";
            }
            if(StringUtils.isNotEmpty(methods)){
                methods=methods.substring(0,methods.length()-1);
            }

            SysResourcePermission resourcePermission = new SysResourcePermission();
            resourcePermission.setRequestTypes(methods);
            //获取Controller的类名
            String controllerClassName = mappingInfoValue.getBeanType().getName();
            Method method = mappingInfoValue.getMethod();
            String requestMethodName = method.getName();
            //获取方法的参数类型
            Class<?>[] methodParamTypes = method.getParameterTypes();
            String paramTypes="";
            for(Class<?> cls : methodParamTypes){
                paramTypes+=cls.getName()+",";
            }
            if(StringUtils.isNotEmpty(paramTypes)){
                paramTypes=paramTypes.substring(0,paramTypes.length()-1);
            }
            resourcePermission.setMethodParamTypes(paramTypes);
            //通过Spring的LocalVariableTableParameterNameDiscoverer类获取方法的参数名称
            LocalVariableTableParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
            //获取方法的参数名称
            String[] methodParamNames = parameterNameDiscoverer.getParameterNames(method);
            String paramNames = "";
            for(String paramName:methodParamNames){
                paramNames+=paramName+",";
            }
            if(StringUtils.isNotEmpty(paramNames)){
                paramNames=paramNames.substring(0,paramNames.length()-1);
            }
            resourcePermission.setMethodParamNames(paramNames);
            resourcePermission.setControllerClassName(controllerClassName);
            resourcePermission.setMethodName(requestMethodName);
            resourcePermission.setCreateTime(new Date());
            resourcePermission.setUpdateTime(new Date());

            PatternsRequestCondition patternsCondition = requestMappingInfo.getPatternsCondition();
            //资源的访问URL
            Set<String> patterns = patternsCondition.getPatterns();
            for (String url : patterns){
                resourcePermission.setRequestUrl(url);
                String perms = url.replaceAll("/",":").replaceFirst(":","");//访问权限
                resourcePermission.setPerms(perms);
            }
            sysResourcePermissions.add(resourcePermission);
        }
        if(CollectionUtils.isNotEmpty(sysResourcePermissions)){
            insertBatchSelective(sysResourcePermissions);//批量保存
            List<SysResource> sysResourceList = new ArrayList<>();
            sysResourcePermissions.forEach(item->{
                SysResource sysResource = new SysResource();
                sysResource.setPerms(item.getPerms());
                sysResource.setUrl(item.getRequestUrl());
                sysResource.setType(Constants.RESOURCE_TYPE.SYS_RESOURCE);
                sysResource.setCreateTime(new Date());
                sysResource.setDeleteFlag(Constants.DELETE_FLAG.NO);
                sysResourceList.add(sysResource);
            });
            SysResourceExample sysResourceExample = new SysResourceExample();
            sysResourceExample.createCriteria().andTypeEqualTo(Constants.RESOURCE_TYPE.SYS_RESOURCE);
            List<SysResource> resourceList = sysResourceService.selectByExample(sysResourceExample);//先获取之前的旧数据
            sysResourceService.deleteByExample(sysResourceExample);//删除所有的系统资源数据
            sysResourceService.insertBatchSelective(sysResourceList);//批量保存
            //为超级管理员授权系统资源
            List<Long> resIds = new ArrayList<>();
            resourceList.forEach(sysResource -> resIds.add(sysResource.getId()));
            SysRoleResourceExample roleResourceExample = new SysRoleResourceExample();
            roleResourceExample.createCriteria().andResourceIdIn(resIds);
            sysRoleResourceService.deleteByExample(roleResourceExample);//删除旧的授权数据
            List<SysRoleResource> sysRoleResources = new ArrayList<>();
            sysResourceList.forEach(item->{
                SysRoleResource sysRoleResource = new SysRoleResource();
                sysRoleResource.setResourceId(item.getId());
                sysRoleResource.setRoleId(Constants.SUPER_ADMIN);
                sysRoleResources.add(sysRoleResource);
            });
            sysRoleResourceService.insertBatchSelective(sysRoleResources);//批量插入
        }
        return sysResourcePermissions;
    }
}